package br.com.leoEarUnpacked.views;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.graphics.Image;
import org.eclipse.jface.action.*;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.*;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.SWT;
import br.com.leoEarUnpacked.preferences.PreferenceConstants;
import br.com.leoEarUnpacked.Activator;


/**
 * This sample class demonstrates how to plug-in a new workbench view. The view
 * shows data obtained from the model. The sample creates a dummy model on the
 * fly, but a real implementation would connect to the model available either in
 * this or another plug-in (e.g. the workspace). The view is connected to the
 * model using a content provider.
 * <p>
 * The view uses a label provider to define how model objects should be
 * presented in the view. Each view can present the same model objects using
 * different labels and icons, if needed. Alternatively, a single label provider
 * can be shared between views in order to ensure that objects of the same type
 * are presented in the same way everywhere.
 * <p>
 */

public class LeoEarUnpackedView extends ViewPart {

	private TableViewer viewer;
	private Action action1;
	private Action action2;
	private Action doubleClickAction;
	private String separator;

	String projectEarName = ""; 							
	String projectWarName = "";  
	String projectEjbName = ""; 
	String jbossFolder = "";			
	String earZipped = "";
	
	/*
	 * The content provider class is responsible for providing objects to the
	 * view. It can wrap existing objects in adapters or simply return objects
	 * as-is. These objects may be sensitive to the current input of the view,
	 * or ignore it and always show the same content (like Task List, for
	 * example).
	 */

	class ViewContentProvider implements IStructuredContentProvider {
		public void inputChanged(Viewer v, Object oldInput, Object newInput) {
		}

		public void dispose() {
		}

		public Object[] getElements(Object parent) {
			return new String[] { PreferenceConstants.ACT_DEPLOY_EAR , PreferenceConstants.ACT_REMOVE_EAR };
		}
	}

	class ViewLabelProvider extends LabelProvider implements
			ITableLabelProvider {
		public String getColumnText(Object obj, int index) {
			return getText(obj);
		}

		public Image getColumnImage(Object obj, int index) {
			return getImage(obj);
		}

		public Image getImage(Object obj) {
			return PlatformUI.getWorkbench().getSharedImages().getImage(
					ISharedImages.IMG_OBJ_ELEMENT);
		}
	}

	class NameSorter extends ViewerSorter {
	}

	/**
	 * The constructor.
	 */
	public LeoEarUnpackedView() {
		if (File.pathSeparator.equals(":")) {
			MyConsole.msg("### (constructor) You are smart!!! using UNIX/LINUX/MAC!!!");
			this.separator = "/";
		} else {
			MyConsole.msg("### (constructor) You are fucked!!! using rWindows!!!");
			this.separator = "\\";
		}		
		
	}

	/**
	 * This is a callback that will allow us to create the viewer and initialize
	 * it.
	 */
	public void createPartControl(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL);
		viewer.setContentProvider(new ViewContentProvider());
		viewer.setLabelProvider(new ViewLabelProvider());
		viewer.setSorter(new NameSorter());
		viewer.setInput(getViewSite());

		// Create the help context id for the viewer's control
		PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(),
				"com.leo.Plug01.viewer");
		makeActions();
		hookContextMenu();
		hookDoubleClickAction();
		contributeToActionBars();
	}

	private void hookContextMenu() {
		MenuManager menuMgr = new MenuManager("#PopupMenu");
		menuMgr.setRemoveAllWhenShown(true);
		menuMgr.addMenuListener(new IMenuListener() {
			public void menuAboutToShow(IMenuManager manager) {
				LeoEarUnpackedView.this.fillContextMenu(manager);
			}
		});
		Menu menu = menuMgr.createContextMenu(viewer.getControl());
		viewer.getControl().setMenu(menu);
		getSite().registerContextMenu(menuMgr, viewer);
	}

	private void contributeToActionBars() {
		IActionBars bars = getViewSite().getActionBars();
		fillLocalPullDown(bars.getMenuManager());
		fillLocalToolBar(bars.getToolBarManager());
	}

	private void fillLocalPullDown(IMenuManager manager) {
		manager.add(action1);
		manager.add(new Separator());
		manager.add(action2);
	}

	private void fillContextMenu(IMenuManager manager) {
		manager.add(action1);
		manager.add(action2);
		// Other plug-ins can contribute there actions here
		manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
	}

	private void fillLocalToolBar(IToolBarManager manager) {
		manager.add(action1);
		manager.add(action2);
	}

	private void makeActions() {
		action1 = new Action() {
			public void run() {
				//showMessage("Action 1 executed");
				actionDeployEar();
			}
		};
		action1.setText( PreferenceConstants.ACT_DEPLOY_EAR );
		action1.setToolTipText("Action 1 tooltip xxxx");
		action1.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
				.getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));

		action2 = new Action() {
			public void run() {
				//showMessage("Action 2 executed");
				actionRemoveEar();
			}
		};
		action2.setText(PreferenceConstants.ACT_REMOVE_EAR);
		action2.setToolTipText("Generate Explode EAR tooltip");
		action2.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
				.getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));
		
		doubleClickAction = new Action() {
			public void run() {
				ISelection selection = viewer.getSelection();
				Object obj = ((IStructuredSelection) selection)
						.getFirstElement();

				//Retrieve param values before every execution
				projectEarName = getProperty(PreferenceConstants.PROJECT_EAR_NAME); //"mobility-ear"; //							
				projectWarName = getProperty(PreferenceConstants.PROJECT_WAR_NAME);  //"mobility-web";
				projectEjbName = getProperty(PreferenceConstants.PROJECT_EJB_NAME); // "mobility-ejb";
				jbossFolder = getProperty(PreferenceConstants.DEPLOY_FOLDER);			
				earZipped = getProperty(PreferenceConstants.EAR_ZIPPED);
				
				if(obj.toString().equals( PreferenceConstants.ACT_DEPLOY_EAR )){
					MyConsole.msg("\n @@@@@@@@@@@ actionDeployEar @@@@@@@@@@@ ");
					actionDeployEar();
				}
				if(obj.toString().equals( PreferenceConstants.ACT_REMOVE_EAR )){
					MyConsole.msg("\n @@@@@@@@@@@ actionRemoveEar @@@@@@@@@@@ ");
					actionRemoveEar();
				}

			}

			
		}; //#### END INNER CLASS doubleClickAction
	}
	
	//############################### DEPLOY ############################
	private void actionDeployEar() {

		if ( isActive() && validateGenerateEarUnpacked() && MessageDialog.openConfirm(viewer.getControl().getShell(),
				PreferenceConstants.PLUG_NAME , "Do you really want to deploy your EAR unpacked?") ) {

			// ## Unzip to Temp EAR
			
			String dest = getProperty(PreferenceConstants.TMP)
					+ separator + projectEarName;
			File fileEarDir = new File(
					getProperty(PreferenceConstants.TMP) + separator
							+ projectEarName);
			File fileEarDEL_folder = new File(
					getProperty(PreferenceConstants.TMP) + separator
							+ projectEarName); //project.ear FOLDER
			
			File fileEarDEL_Zipped = new File(
					getProperty(PreferenceConstants.TMP) + separator
							+ projectEarName + ".ear");//project.ear ZIPED FILE
			if (fileEarDEL_folder.exists()) { // exists
				if (deleteDirectory(fileEarDEL_folder)) {
					MyConsole.msg("### Deleted: " + fileEarDEL_folder);
				}
			}
			if (fileEarDEL_Zipped.exists()) { // exists
				if (deleteDirectory(fileEarDEL_Zipped)) {
					MyConsole.msg("### Deleted: " + fileEarDEL_Zipped);
				}
			}
			if (fileEarDir.mkdir()) {
				MyConsole.msg("### New dir created: " + fileEarDir);
				MyConsole.msg("### Start extracting EAR... ");
				try {
					unzipFile(earZipped, dest);
					// ### WAR ###
					MyConsole.msg("### Start extracting WAR... ");
					File fileWarDest = new File(dest + separator
							+ projectWarName);
					File fileWar = new File(dest + separator
							+ projectWarName + ".war");
					fileWarDest.mkdir();
					unzipFile(fileWar.getAbsolutePath(), fileWarDest
							.getAbsolutePath());
					

					
					fileWar = doItwhenIsFuckingWindows(fileWar);
					/*
					if(separator.equals("\\")){
						fileWar = null;
						fileWar = new File(dest + separator
								+ projectWarName + ".war");
						try {
							Thread.sleep(2000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					*/
					if(!fileWar.delete()){
						MyConsole.msg("######### Mother Fucking! coundn't delete zipped war... Will try again... " + fileWar);
						if(!new File(fileWar.getAbsolutePath()).delete()){
							File fdp = new File(dest + separator + projectWarName + ".war");
							if(!fdp.delete()){
								MyConsole.msg("######### Mother Fucking! Fucking hell!!! Coulndn't again!!! " + fdp);
							}
						}
							
					}
									
					fileWarDest.renameTo(new File(fileWarDest
							.getAbsolutePath()
							+ ".war"));
					MyConsole.msg("### WAR extracted... ");

					// ### EJB ###
					MyConsole.msg("### Start extracting EJB... ");
					File fileEjbDest = new File(dest + separator
							+ projectEjbName);
					File fileEjb = new File(dest + separator
							+ projectEjbName + ".jar");
					fileEjbDest.mkdir();
					unzipFile(fileEjb.getAbsolutePath(), fileEjbDest
							.getAbsolutePath());
					
					fileEjb = doItwhenIsFuckingWindows(fileEjb);
					/*	
					if(separator.equals("\\")){						
						fileEjb = null;
						fileEjb = new File(dest + separator
								+ projectEjbName + ".jar");
						
						try {
							Thread.sleep(2000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					*/
					if(!fileEjb.delete()){
						MyConsole.msg("######### Mother Fucking! coundn't delete zipped ejb... " + fileEjb);
						File fdpEjb = new File(dest + separator
								+ projectEjbName + ".jar");
						if(!fdpEjb.delete()){
							MyConsole.msg("######### Fuck! Fuck! coundn't delete zipped ejb again... ");	
						}
					}
					
					fileEjbDest.renameTo(new File(fileEjbDest
							.getAbsolutePath()
							+ ".jar"));
					MyConsole.msg("### EJB extracted... ");
					// Rename EAR
					File earToBeRenamed = new File(dest);
	
					MyConsole.msg("### End extracting.");
					//## Copy EAR unpacked to JBoss folder
					MyConsole.msg("### Copying EAR unpacked to JBoss folder...");
					
					File oldEar = new File(jbossFolder + separator + projectEarName + ".ear");
					
					//doItwhenIsFuckingWindows(oldEar);
					deleteEar(oldEar);
					/*
					File oldEar = new File(jbossFolder + separator + projectEarName + ".ear");
					if(oldEar.exists()){
						if(oldEar.isDirectory()){
							deleteDirectory(oldEar);
						}else{
							oldEar.delete(); //isFile
						}
						if(!oldEar.exists()){
							System.out.println("### Old EAR deleted from deploy folder...");
						}
					}
					*/
												
					if(earToBeRenamed.renameTo( new File(jbossFolder + separator + projectEarName + ".ear") )){
						MyConsole.msg("### EAR successfully generated and deployed!!!");
						showMessage("EAR successfully generated and deployed!");
					}else{
						showMessage("Problem! EAR is not there!");
					}

				} catch (IOException e) {
					showMessage("Erro to unzip file. " + e);
					MyConsole.msg(e.toString());
				}
				
			}

		}// End validation

		
	}
	
	File doItwhenIsFuckingWindows(File file){
		if(separator.equals("\\")){
			String str = file.getAbsolutePath();
			file = null;
			file = new File(str);
		}
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return file;
	}
	
	private void actionRemoveEar(){
		if(MessageDialog.openConfirm(viewer.getControl().getShell(),
				PreferenceConstants.PLUG_NAME , "Are you sure you want to UNDEPLOY your EAR?") ){						
			File file = new File(jbossFolder + separator + projectEarName + ".ear");
			MyConsole.msg("### Will try to delete: " + file);
			if (deleteEar(file)){
				MyConsole.msg("### EAR has been removed!(or didn't exist before)!!!");
				showMessage("EAR has been removed!(or didn't exist before)");
			}else{
				MyConsole.msg("### Couldn't delete: " + file);
			}
		}			
	}

	private boolean deleteEar(File file){
		boolean res = false;
		if(file.exists()){
			if(file.isDirectory()){
				deleteDirectory(file);
			}else{
				file.delete(); //isFile
			}
			if(!file.exists()){//Just to confirm if is not there...
				MyConsole.msg("### Old EAR deleted from deploy folder...");
				res = true;
			}
		}else{
			MyConsole.msg("### File doesn't exist in deploy folder...");
			res = true;
		}
		return res;
	}
	
	static public boolean deleteDirectory(File path) {
		if (path.exists()) {
			File[] files = path.listFiles();
			for (int i = 0; i < files.length; i++) {
				if (files[i].isDirectory()) {
					deleteDirectory(files[i]);
				} else {
					files[i].delete();
				}
			}
		}
		return (path.delete());
	}

	private void unzipFile(String zippedFile, String dirDest) throws IOException {
		//final int BUFFER = 2048;
		File fileToUnpack = null;
		ZipFile zip = null;
		String entryName = null; // will stay null if unzip whole file

		zip = new ZipFile(zippedFile);
		if (entryName == null) { // unpack whole file
			Enumeration en = zip.entries();
			while (en.hasMoreElements()) {
				ZipEntry entry = (ZipEntry) en.nextElement();
				if (entry.isDirectory()) {
					//System.out.println("directory ignored: " + entry.toString());
					continue;
				}

				InputStream stm;
				try {
					stm = zip.getInputStream(entry);
				} catch (java.io.IOException e) {
					showMessage("Cannot get input stream for '" 
							+ entry.toString() + "' in zip file '"
							+ fileToUnpack.getAbsolutePath());
					MyConsole.msg("Cannot get input stream for '"
							+ entry.toString() + "' in zip file '"
							+ fileToUnpack.getAbsolutePath());
					return;
				}
				String targetFilename = dirDest + "/" + entry.toString();
				// create dir if needed
				int lastSlash = targetFilename.lastIndexOf("/");
				if (lastSlash > 0) {
					String dirName = targetFilename.substring(0, lastSlash);
					new File(dirName).mkdirs();
				}
				// Copy zip entry to output directory
				if (File.pathSeparator.equals(":")) {
					// System.out.println("@@@@ MAC");
				} else { // rWindows
					// System.out.println("@@@@ Win");
					targetFilename = targetFilename.replace('/', '\\');
				}
				streamToFile(stm, targetFilename);
			}

		}// end if zao

		fileToUnpack = null;
		zip = null;
	}

	private void streamToFile(InputStream stm, String targetFilename) {
		FileOutputStream stmOut = null;
		byte[] buffer = new byte[2048];
		int bytecount;

		try {
			stmOut = new FileOutputStream(new File(targetFilename));
		} catch (java.io.IOException e) {
			showMessage("Error opening output file '" + targetFilename
					+ "': " + e.toString());
			MyConsole.msg("Error opening output file '" + targetFilename
					+ "': " + e.toString());
			System.exit(101);
		}
		try {
			while ((bytecount = stm.read(buffer)) > 0) {
				stmOut.write(buffer, 0, bytecount);
			}
			stmOut.close();
		} catch (java.io.IOException e) {
			MyConsole.msg("Error writing output file '" + targetFilename
					+ "': " + e.toString());
			System.exit(101);
		}
	}

	public void copyFile(File source, File dest) throws IOException {
		FileChannel in = null, out = null;
		try {
			in = new FileInputStream(source).getChannel();
			out = new FileOutputStream(dest).getChannel();

			long size = in.size();
			MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0,
					size);

			out.write(buf);

		} finally {
			if (in != null)
				in.close();
			if (out != null)
				out.close();
		}
	}

	private boolean validateGenerateEarUnpacked() {
		boolean res = true;
		List<String> erroList = new ArrayList<String>();
		
		if (getProperty(PreferenceConstants.PROJECT_EAR_NAME).equals("")) {
			erroList.add("Temp Ear Project Name is empty");
		}
		if (getProperty(PreferenceConstants.PROJECT_WAR_NAME).equals("")) {
			erroList.add("Temp War Project Name is empty");
		}
		if (getProperty(PreferenceConstants.PROJECT_EJB_NAME).equals("")) {
			erroList.add("Temp EJB Prject Name is empty");
		}
		if (getProperty(PreferenceConstants.TMP).equals("")) {
			erroList.add("Temp Directory is empty");
		}
		if (getProperty(PreferenceConstants.EAR_ZIPPED).equals("")) {
			erroList.add("EAR file not specified");
		}
		if (erroList.size() != 0) {
			String msgFinal = "Errors: " + erroList.size() + "\n";
			for (String msg : erroList) {
				msgFinal = msgFinal + " --> " + msg + "\n";
			}
			showMessage(msgFinal);
			res = false;
		}
		return res;
	}
	
	private boolean isActive() {		
		Boolean isPluginActive = new Boolean ( getProperty(PreferenceConstants.ACTIVE) );
		if(!isPluginActive)
			showMessage("Plugin is NOT active. Go to preferences and active this plugin.");	
		return isPluginActive;
	}

	public String getProperty(String value) {
		Activator activator = Activator.getDefault();
		return activator.getPluginPreferences().getString(value);
	}

	private void hookDoubleClickAction() {
		viewer.addDoubleClickListener(new IDoubleClickListener() {
			public void doubleClick(DoubleClickEvent event) {
				doubleClickAction.run();
			}
		});
	}

	private void showMessage(String message) {
		MessageDialog.openInformation(viewer.getControl().getShell(),
				PreferenceConstants.PLUG_NAME , message);
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}
}